/*************************************************
* Title：TinyToolKit
* Author：Opportunity 
* Discribe：实现环形菜单功能
* CreateTime：2020-05-16 21:30:47
* Version：1.0
* Modify Recoder：
*************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using TinyToolKit.Sound;
using UnityEngine;
using UnityEngine.UI;

namespace TinyToolKit
{
    public class TinyPieMenu : MonoBehaviour
    {
        [Header("Setting")]
        public Color normalColor = Color.blue; 
        public Color highlightedColor = Color.red;
        public Color pressedColor = Color.white;  
        public Color disabledColor = Color.gray;  
    
        public float pieRadius = 80; 
        public float pieScale = 1; 
        public bool snap = true;
        public bool tiltTowardMouse = true;
        public float tiltAmount = 10; 
        public bool useSeparators;
        public GameObject separatorPrefab;
        [SerializeField] private List<GameObject> pieButtons;
        
        [Header("FxSound")]
        public AudioClip switchSound;
        public AudioClip clickSound; 

        private Image _cursor;
        private Transform _buttonsRoot;
        private Transform _separatorsRoot; 
        private float _targetFillAmount;
        private List<TinyPieButton> _pieBtns;
        private GameObject _selectedSeg;
        private bool isOpened;
        private TSoundManager _soundManager;
        
        private void Awake()  
        {
            _pieBtns = new List<TinyPieButton>();

            _cursor = transform.Find("Cursor").GetComponent<Image>();
            _buttonsRoot = transform.FindOrCreate("Buttons");
            _separatorsRoot = transform.FindOrCreate("Separators");
            
            SpawnPieMenu(pieButtons.Count);
        }

        private void Start()
        {
            _soundManager = TinyTool.Instance.GetManager<TSoundManager>();
        }

        public void AddPieButton(GameObject btn)
        {
            if (pieButtons.Contains(btn) == false)
            {
                pieButtons.Add(btn); 
                SpawnPieMenu(pieButtons.Count);
            }
        }

        public void Open()
        {
            isOpened = true;
            gameObject.SetActive(true);
        }

        public void Close()
        {
            isOpened = false;
            gameObject.SetActive(false);
        }

        #region Internal Func
        private void SpawnPieMenu(int btnCount)
        {
            if (btnCount >= 2 && btnCount <= 12)
            {
                foreach (Transform sep in _separatorsRoot)
                {
                    Destroy(sep.gameObject);
                }
                foreach (Transform btn in _buttonsRoot)
                {
                    Destroy(btn.gameObject);
                }
                _pieBtns.Clear();

                _targetFillAmount = 1.0f / pieButtons.Count;
                float fillAngle = _targetFillAmount * 360f;
                float preAngle = 0;
                for (int i = 0; i < pieButtons.Count; i++)
                {
                    GameObject btn = GameObject.Instantiate(pieButtons[i], Vector3.zero, transform.rotation,_buttonsRoot);
                    float targetRot = preAngle + fillAngle / 2;
                    targetRot %= 360;
                    TinyPieButton pieBtn = btn.GetOrAddComponent<TinyPieButton>();
                    pieBtn.RotAngle = targetRot;
                    _pieBtns.Add(pieBtn);
                    preAngle = targetRot + fillAngle / 2;
                    btn.transform.localPosition = new Vector2(pieRadius * Mathf.Cos((targetRot - 90) * Mathf.Deg2Rad), -pieRadius * Mathf.Sin((targetRot - 90) * Mathf.Deg2Rad));

                    if (useSeparators && separatorPrefab != null)
                    {
                        GameObject sep = GameObject.Instantiate(separatorPrefab, Vector3.zero, Quaternion.identity);
                        sep.transform.SetParent(_separatorsRoot, false);
                        sep.transform.localRotation = Quaternion.Euler(0, 0, preAngle);
                    }
                }
            }
        }

        private GameObject GetNearestSeg(float mouseRotation) 
        {
            GameObject nearest = null;
            float difference = Mathf.Infinity;
            for (int i = 0; i < _pieBtns.Count; i++)
            {
                GameObject pieBtn = _pieBtns[i].gameObject;
                float rotation = pieBtn.GetComponent<TinyPieButton>().RotAngle;
                if (Mathf.Abs(rotation - mouseRotation) < difference)
                {
                    nearest = pieBtn;
                    difference = Mathf.Abs(rotation - mouseRotation);
                }
            }

            return nearest;
        }

        #endregion
        

        private void Update()
        {
            if (isOpened == false) return;
            
            //修改扇形指针的大小
            if (Mathf.Abs(_cursor.fillAmount - _targetFillAmount) > 0.01f)
                _cursor.fillAmount = Mathf.Lerp(_cursor.fillAmount, _targetFillAmount, Time.deltaTime * 3);

            //获取鼠标在以屏幕中心点为轴心点的坐标系中的位置
            Vector3 screenCenter = new Vector3((float)Screen.width / 2f, (float)Screen.height / 2f, 0f);
            Vector3 vector = Input.mousePosition - screenCenter; 

            //是否偏向鼠标
            if (tiltTowardMouse)
            {
                float x = vector.x / screenCenter.x; 
                float y = vector.y / screenCenter.y;
                transform.localRotation = Quaternion.Slerp(transform.localRotation, Quaternion.Euler(new Vector3(-y, x, 0) * tiltAmount), Time.deltaTime * 3);
            }
            
            //以屏幕中心点为轴心点的坐标系中,鼠标旋转角度
            float mouseRotation = Mathf.Atan2(vector.x, vector.y) * Mathf.Rad2Deg;
            //将范围-180至0转化为180至360的范围
            if (mouseRotation < 0f)
                mouseRotation += 360f;

            //获取距离鼠标角度最近的按钮
            GameObject newSeg = GetNearestSeg(mouseRotation);
            if (newSeg != null && newSeg != _selectedSeg)
            {
                if (switchSound != null)
                    _soundManager.PlayUISound(switchSound);
                _selectedSeg = newSeg;
            }

            if (_selectedSeg == null) return;

            //更新扇形指针旋转角度
            float cursorRotation;
            if (snap)
                cursorRotation = -(_selectedSeg.GetComponent<TinyPieButton>().RotAngle - _cursor.fillAmount * 360f / 2f);
            else
                cursorRotation = -(mouseRotation - _cursor.fillAmount * 360f / 2f);
            
            _cursor.transform.localRotation = Quaternion.Slerp(_cursor.transform.localRotation, Quaternion.Euler(0, 0, cursorRotation), Time.deltaTime * 5);
            
            //按钮颜色调整
            for (int i = 0; i < pieButtons.Count; i++)
            {
                TinyPieButton pieBtn = _pieBtns[i];
                Image pieBtnImg = pieBtn.GetComponent<Image>();
                if (pieBtn.gameObject != _selectedSeg)
                { 
                    if (pieBtn.interactable)
                        pieBtnImg.color = Color.Lerp(pieBtnImg.color, normalColor, Time.deltaTime * 3);
                    else
                        pieBtnImg.color = Color.Lerp(pieBtnImg.color, disabledColor, Time.deltaTime * 3);
                }
                else
                {
                    pieBtnImg.color = Color.Lerp(pieBtnImg.color, pressedColor, Time.deltaTime * 3);
                }
            }

            //根据当前按钮是否可操作，调整扇形指针的颜色
            if (_selectedSeg.GetComponent<TinyPieButton>().interactable)
                _cursor.color = Color.Lerp(_cursor.color, highlightedColor, Time.deltaTime * 3);
            else
                _cursor.color = Color.Lerp(_cursor.color, disabledColor, Time.deltaTime * 3);
            
            //鼠标按下时，调整扇形指针的位置
            if (Input.GetMouseButton(0))
            {
                _cursor.rectTransform.localScale = Vector3.Lerp(_cursor.rectTransform.localScale,Vector3.one * 1.05f, Time.deltaTime * 6);
            }
            else
            {
                if(Vector3.Distance(_cursor.rectTransform.localScale,Vector3.one) > 0.01f)
                    _cursor.rectTransform.localScale = Vector3.Lerp(_cursor.rectTransform.localScale, Vector3.one, Time.deltaTime * 4);
            }
            
            //鼠标抬起时，调用TinyPieButton的方法
            if (Input.GetMouseButtonUp(0))
            {
                if (_selectedSeg.GetComponent<TinyPieButton>().interactable)
                {
                    _selectedSeg.GetComponent<TinyPieButton>().OnClick();
                }

                if (clickSound != null) 
                    _soundManager.PlayUISound(clickSound);
            }
        }
    }
}
